package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.dto.PageDTO;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.exceptions.LyException;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_UP_KEY;

@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private AmqpTemplate amqpTemplate;


    @Override
    public PageDTO<SpuDTO> querySpuByPage(Long brandId, Long categoryId, Long id, Integer page, Integer rows, Boolean saleable) {
        //SELECT * FROM tb_spu s
        //where
        Page<Spu> page1 = query().eq(id != null, "id", id)
                //# s.id = 1 and
                .eq(categoryId != null, "cid3", categoryId)
                //s.cid3 =76 and
                .eq(brandId != null, "brand_id", brandId)
                //s.brand_id = 18374 and
                .eq(saleable != null, "saleable", saleable)
                //s.saleable = true
                .page(new Page<>(page, rows));
        //limit 0,5
        long total = page1.getTotal();
        long totalPage = page1.getPages();
        List<Spu> list = page1.getRecords();
        List<SpuDTO> spuDTOList = SpuDTO.convertEntityList(list);
        for (SpuDTO spuDTO : spuDTOList) {
            queryBrandAndCategoryName(spuDTO);
        }

        return new PageDTO<>(total, totalPage, spuDTOList);

    }

    @Override
    @Transactional
    public void addGoods(SpuDTO spuDTO) {
        //新增spu
        Spu spu = spuDTO.toEntity(Spu.class);
        spu.setSaleable(false);
        boolean result = save(spu);
        if (result == false) {
            throw new LyException(500, "新增商品失败");
        }
        //新增spudetail
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        result = spuDetailService.save(spuDetail);
        if (result == false) {
            throw new LyException(500, "新增商品失败");
        }
        //新增sku
        List<Sku> list = spuDTO.getSkus().stream().map(skuDTO -> {
            Sku sku = skuDTO.toEntity(Sku.class);
            sku.setSpuId(spu.getId());
            sku.setSaleable(false);
            return sku;
        }).collect(Collectors.toList());
        //批量新增
        skuService.saveBatch(list);
    }

    /**
     * 商品上下架
     * @param spuId
     * @param saleable
     */
    @Override
    public void saleable(Long spuId, Boolean saleable) {
        //更新spu
        Spu spu = new Spu();
        spu.setId(spuId);
        spu.setSaleable(saleable);
        boolean b = updateById(spu);
        if (b==false){
            throw new LyException(500,"更新失败");
        }
        //更新sku
        if (skuService.update().eq("spu_id",spuId).set("saleable",saleable).update()==false){
            throw new LyException(500,"更新失败");
        }
        //发送消息
        String routingKey = saleable ? ITEM_UP_KEY : ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME, routingKey, spuId);

    }

    @Override
    public SpuDTO queryGoodsById(Long id) {
        //查询spu
        Spu spu = getById(id);
        if (spu==null){
            throw new LyException(400,"商品id不存在");
        }
        SpuDTO spuDTO = new SpuDTO(spu);
        //查询spuDetail
        SpuDetail detail = spuDetailService.getById(id);
        if (detail==null){
            throw new LyException(400,"商品id不存在");
        }
        spuDTO.setSpuDetail(new SpuDetailDTO(detail));
        //查询sku
        List<Sku> list = skuService.query().eq("spu_id", id).list();
        if (CollectionUtils.isEmpty(list)){
            throw new LyException(400,"商品id不存在");
        }
        spuDTO.setSkus(SkuDTO.convertEntityList(list));

        //准备商品分类和品牌名称
        handleCategoryAndBrandName(spuDTO);
        
        return spuDTO;
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        //判断是否存在spu的id，有说明需要修改，没有说明不需要
        Long spuId = spuDTO.getId();
        if (spuId!=null){
            //spu需要修改，更新spu，转换dto
            Spu spu = spuDTO.toEntity(Spu.class);
            //更新
            boolean success = updateById(spu);
            if (!success){
                //更新失败，抛出异常
                throw new LyException(500,"更新商品失败");
            }
        }
        //修改spuDetail
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        //判断是否为null
        if (detailDTO!=null && detailDTO.getSpuId()!=null){
            //spuDetail不存在，需要修改，转换dto
            SpuDetail detail = detailDTO.toEntity(SpuDetail.class);
            boolean success = spuDetailService.updateById(detail);
            if (!success){
                //更新失败
                throw new LyException(500,"更新商品失败");
            }
            //修改sku
            List<SkuDTO> dtoList = spuDTO.getSkus();
            //判断是否包含sku
            if (CollectionUtils.isEmpty(dtoList)){
                return;
            }
            //转换dto，并将sku根据saleable是否为null来分组。null，是新增或修改，不是null是删除
            Map<Boolean, List<Sku>> map = dtoList.stream().map(skuDTO -> skuDTO.toEntity(Sku.class))
                    .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));
            //获取要新增或修改的sku
            List<Sku> insertOrUpdateList = map.get(true);
            //如果不为空，则修改或新增
            if (!CollectionUtils.isEmpty(insertOrUpdateList)){
                skuService.saveOrUpdateBatch(insertOrUpdateList);
            }
            //获取要删除的sku
            List<Sku> deleteSkuList = map.get(false);
            if (!CollectionUtils.isEmpty(deleteSkuList)){
                //存在要删除的sku
                List<Long> idlList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
                //删除
                skuService.removeByIds(idlList);
            }
        }
    }

    private void handleCategoryAndBrandName(SpuDTO spuDTO) {
        //根据品牌id查询品牌名称
        Brand brand = brandService.getById(spuDTO.getBrandId());
        if (brand!=null){
            spuDTO.setBrandName(brand.getName());
        }
        //根据三级分类id查询分类集合
        List<Category> categories = categoryService.listByIds(spuDTO.getCategoryIds());
        if (!CollectionUtils.isEmpty(categories)){
            //取出分类的名称
            String collect = categories.stream().map(Category::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(collect);
        }
    }
    private void queryBrandAndCategoryName(SpuDTO spuDTO) {
        //添加分类名称
        //获取商品关联的三级的分类的id集合
        List<Long> categoryIds = spuDTO.getCategoryIds();
        //查询三级分类的集合
        List<Category> categories = categoryService.listByIds(categoryIds);
        if (!CollectionUtils.isEmpty(categories)) {
            String names = categories.stream().map(Category::getName).collect(Collectors.joining(">"));
            spuDTO.setCategoryName(names);
        }
//        StringBuilder sb = new StringBuilder();
//        for (Category category : categories) {
//            sb.append(category.getName()).append(">");
//        }
//        sb.deleteCharAt(sb.length()-1);
//        spuDTO.setCategoryName(sb.toString());
        //添加品牌名称
        Long brandId = spuDTO.getBrandId();
        Brand brand = brandService.getById(brandId);
        if (brand != null) {
            spuDTO.setBrandName(brand.getName());
        }
    }
}